package com.cool.modules.finance.service.account.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.exception.CoolException;
import com.cool.core.util.CoolSecurityUtil;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.service.sys.BaseSysUserService;
import com.cool.modules.finance.constant.AccountType;
import com.cool.modules.finance.constant.OrderType;
import com.cool.modules.finance.constant.TransferType;
import com.cool.modules.finance.dto.FinancePaymentAccountVo;
import com.cool.modules.finance.dto.FinanceTransferAccountVo;
import com.cool.modules.finance.dto.TreeAccountVo;
import com.cool.modules.finance.entity.account.FinanceAccountEntity;
import com.cool.modules.finance.entity.account.FinanceTransferAccountEntity;
import com.cool.modules.finance.entity.account.FinanceTrialBalanceEntity;
import com.cool.modules.finance.entity.family.FinanceUserFamilyEntity;
import com.cool.modules.finance.mapper.account.FinanceAccountMapper;
import com.cool.modules.finance.mapper.account.FinanceTrialBalanceMapper;
import com.cool.modules.finance.mapper.family.FinanceUserFamilyMapper;
import com.cool.modules.finance.service.account.FinanceAccountService;
import com.cool.modules.finance.service.account.FinanceTransferAccountService;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author todd
 * @description: 账务服务实现类
 */
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
@Slf4j
public class FinanceAccountServiceImpl extends BaseServiceImpl<FinanceAccountMapper, FinanceAccountEntity> implements FinanceAccountService {

    final FinanceTransferAccountService transferAccountService;

    final FinanceUserFamilyMapper userFamilyMapper;

    final BaseSysUserService sysUserService;

    final FinanceTrialBalanceMapper trialBalanceMapper;

    @Override
    public Long add(FinanceAccountEntity entity) {
        if (null == entity.getAccountCode()) {
            entity.setAccountCode(PinyinUtil.getFirstLetter(entity.getAccountName(), ""));
        }
        if (null == entity.getHotOrder()) {
            entity.setHotOrder(0L);
        }
        if (null == entity.getAccountMoney()) {
            entity.setAccountMoney(new BigDecimal(0));
        }
        if (null == entity.getIsCancel()) {
            entity.setIsCancel(0);
        }
        if (null == entity.getOwnedAccount()) {
            entity.setOwnedAccount(CoolSecurityUtil.getCurrentUserId());
        }
//        if (exists(new QueryWrapper().eq(FinanceAccountEntity::getAccountName, entity.getAccountName()))) {
//            throw new CoolException("该账户名称已存在,请修改账户名称");
//        }
        //理财账户
        if (null != entity.getAccountType() && entity.getAccountType() == 3) {
            if (null == entity.getValueDate()) {
                entity.setValueDate(new Date());
            }
            if (null == entity.getStartRate() || null == entity.getEndRate()) {
                throw new CoolException("预计利率区间不能为空");
            }
            if (entity.getStartRate().compareTo(entity.getEndRate()) > 0) {
                throw new CoolException("预计利率区间需要为正向区间值");
            }
            if (null != entity.getPayAccount()) {
                FinanceTransferAccountVo transferAccountVo = new FinanceTransferAccountVo();
                transferAccountVo.setOutAccountId(entity.getPayAccount());
                transferAccountVo.setTransferMoney(entity.getAccountBalance());
                transferAccountVo.setInAccountUserId(entity.getOwnedAccount());
                entity.setAccountBalance(BigDecimal.ZERO);
                if (!checkBalance(transferAccountVo)) {
                    throw new CoolException("支付账户余额不足,请重新选择");
                }
                //执行了账户添加操作
                Long id = super.add(entity);
                if (null != entity.getAccountType() && entity.getAccountType() == 3 && null != entity.getPayAccount()) {
                    transferAccountVo.setTransferType(1);
                    transferAccountVo.setInAccountId(id);
                    transferAccountVo.setRemark("理财账户初始化转账");
                    if (!checkBalanceAndTransfer(transferAccountVo, true)) {
                        throw new CoolException("支付账户余额不足,请重新选择");
                    }
                }
                return id;
            }
        }
        return super.add(entity);
    }

    @Override
    public boolean update(FinanceAccountEntity entity) {
        entity.setAccountCode(PinyinUtil.getFirstLetter(entity.getAccountName(), ""));
        if (entity.getIsCancel() == 1) {
            entity.setCancelDate(new Date());
        }
        return super.update(entity);
    }

    @Override
    public boolean checkBalance(FinanceTransferAccountVo financeTransferAccountVo) {
        FinanceAccountEntity outAccount = mapper.selectOneById(financeTransferAccountVo.getOutAccountId());
        return null != outAccount && outAccount.getAccountBalance().compareTo(financeTransferAccountVo.getTransferMoney()) >= 0;
    }

    @Override
    public boolean checkBalanceAndTransfer(FinanceTransferAccountVo financeTransferAccountVo, boolean saveRecord) {
        if (checkBalance(financeTransferAccountVo)) {
            FinanceAccountEntity outAccount = mapper.selectOneById(financeTransferAccountVo.getOutAccountId());
            financeTransferAccountVo.setOutAccountUserId(outAccount.getOwnedAccount());
            FinanceAccountEntity inAccount = mapper.selectOneById(financeTransferAccountVo.getInAccountId());
            //执行交易
            log.info("执行转账校验：支出账户:{} 收入账户:{} 转账金额:{}", outAccount.getAccountName(), inAccount.getAccountName(), financeTransferAccountVo.getTransferMoney());
            outAccount.setAccountBalance(outAccount.getAccountBalance().subtract(financeTransferAccountVo.getTransferMoney()));
            inAccount.setAccountBalance(inAccount.getAccountBalance().add(financeTransferAccountVo.getTransferMoney()));
            mapper.update(outAccount);
            mapper.update(inAccount);
            log.info("执行转账操作成功");
            if (saveRecord) {
                //记录交易记录
                transferAccountService.saveRecord(financeTransferAccountVo);
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean checkBalanceAndPayment(FinancePaymentAccountVo financePaymentAccountVo) {
        //获取账户信息
        FinanceAccountEntity account = getById(financePaymentAccountVo.getAccountId());
        if (financePaymentAccountVo.getOrderType().equals(OrderType.EXPEND)) {
            //支出操作
            FinanceTransferAccountVo params = new FinanceTransferAccountVo();
            params.setOutAccountId(financePaymentAccountVo.getAccountId());
            params.setTransferMoney(financePaymentAccountVo.getOrderMoney());
            if (!checkBalance(params)) {
                throw new CoolException("支付账户余额不足,请重新选择");
            }
            account.setAccountBalance(account.getAccountBalance().subtract(financePaymentAccountVo.getOrderMoney()));
        } else if (financePaymentAccountVo.getOrderType().equals(OrderType.INCOME)) {
            //收入操作
            account.setAccountBalance(account.getAccountBalance().add(financePaymentAccountVo.getOrderMoney()));
        }
        //更新使用热度
        account.setHotOrder(account.getHotOrder() + 1);
        log.info("执行支付操作，支付账户:{} 支付金额:{}", account.getAccountName(), financePaymentAccountVo.getOrderMoney());
        updateById(account);
        log.info("支付完成");
        return true;
    }

    /**
     * 平账操作
     * @param transferAccountVo
     * @param inAccount
     * @return
     */
    public boolean balanceAccount(FinanceTransferAccountVo transferAccountVo, FinanceAccountEntity inAccount) {
        BigDecimal transferMoney = transferAccountVo.getTransferMoney().subtract(inAccount.getAccountBalance());
        inAccount.setAccountBalance(transferAccountVo.getTransferMoney());
        updateById(inAccount);
        transferAccountVo.setOutAccountUserId(transferAccountVo.getInAccountUserId());
        transferAccountVo.setTransferTime(null == transferAccountVo.getTransferTime() ? new Date() : transferAccountVo.getTransferTime());
        transferAccountVo.setTransferMoney(transferMoney);
        transferAccountVo.setRemark(null == transferAccountVo.getRemark() ? "平账操作自动记录" : transferAccountVo.getRemark());
        transferAccountService.saveRecord(transferAccountVo);
        return true;
    }

    @Override
    public List<TreeAccountVo> treeAccount(JSONObject requestParams) {
        if (!requestParams.containsKey("key")) {
            FinanceUserFamilyEntity userFamilyEntity = userFamilyMapper.selectOneByQuery(new QueryWrapper().eq(FinanceUserFamilyEntity::getUserId, CoolSecurityUtil.getCurrentUserId()));
            if (null != userFamilyEntity) {
                List<Long> owneds = list(new QueryWrapper().select(FinanceAccountEntity::getOwnedAccount).groupBy(FinanceAccountEntity::getOwnedAccount)).stream().map(FinanceAccountEntity::getOwnedAccount).toList();
                List<Long> userIds = userFamilyMapper.selectListByQuery(new QueryWrapper().eq(FinanceUserFamilyEntity::getFamilyId, userFamilyEntity.getFamilyId())).stream().filter(x -> owneds.contains(x.getUserId())).map(FinanceUserFamilyEntity::getUserId).toList();
                return sysUserService.list(new QueryWrapper().in(BaseSysUserEntity::getId, userIds)).stream().map(user -> new TreeAccountVo(user.getId(), user.getUsername() + "-" + user.getName(), false,true)).toList();
            }
        } else {
            FinanceAccountEntity currentAccount = getById(requestParams.getLong("accountId"));
            return list(new QueryWrapper().
                    eq(FinanceAccountEntity::getOwnedAccount, requestParams.getLong("key")).
                    eq(FinanceAccountEntity::getIsCancel, false).
                    eq(FinanceAccountEntity::getCoinId, currentAccount.getCoinId()).
                    ne(FinanceAccountEntity::getId, requestParams.getLong("accountId")).
                    orderBy(FinanceAccountEntity::getAccountType, true)).stream().map(account -> {
                String label = account.getAccountName();
                if (account.getAccountType().equals(AccountType.DEBIT.getType())) {
                    label += "-欠款:" + account.getAccountMoney().subtract(account.getAccountBalance()) + "元";
                }
                return new TreeAccountVo(account.getId(), label, true, false);
            }).toList();
        }
        return null;
    }

    @Override
    public Object transfer(FinanceTransferAccountVo transferAccountVo) {
        FinanceAccountEntity inAccount = getById(transferAccountVo.getInAccountId());
        transferAccountVo.setInAccountUserId(inAccount.getOwnedAccount());
        //平账操作
        if (transferAccountVo.getTransferType().equals(TransferType.BALANCE_ACCOUNT.getType())) {
            return balanceAccount(transferAccountVo, inAccount);
        }
        FinanceAccountEntity outAccount = getById(transferAccountVo.getOutAccountId());
        transferAccountVo.setOutAccountUserId(outAccount.getOwnedAccount());
        //当入账账户为借记账户时，为还款操作
        if (inAccount.getAccountType().equals(AccountType.DEBIT.getType())) {
            transferAccountVo.setTransferType(TransferType.REPAYMENT_BACK.getType());
        }
        return checkBalanceAndTransfer(transferAccountVo, true);
    }

    @Override
    public Object delTransfer(JSONObject requestParams) {
        if (requestParams.containsKey("id")) {
            FinanceTransferAccountEntity record = transferAccountService.getById(requestParams.getLong("id"));
            if (null != record) {
                FinanceTransferAccountVo transferAccountVo = new FinanceTransferAccountVo();
                BeanUtil.copyProperties(record, transferAccountVo);
                transferAccountVo.setInAccountId(record.getOutAccount());
                transferAccountVo.setOutAccountId(record.getInAccount());
                transferAccountVo.setTransferMoney(record.getRepayMoney());
                transferAccountVo.setInAccountUserId(record.getOutAccountUserId());
                transferAccountVo.setOutAccountUserId(record.getInAccountUserId());
                if (!checkBalanceAndTransfer(transferAccountVo, false)) {
                    throw new CoolException("撤销账户余额不足,删除失败");
                }
                //执行逻辑删除
                record.setIsDel(true);
                return transferAccountService.update(record);
            }
            throw new CoolException("转账记录不存在，删除失败");
        }
        throw new CoolException("转账记录id不能为空，删除失败");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Object redeemAccount(JSONObject requestParams) {
        if (!requestParams.containsKey("id")) {
            throw new CoolException("id不能为空");
        }
        //获得试算的信息
        FinanceTrialBalanceEntity trialBalance = trialBalanceMapper.selectOneById(requestParams.getLong("id"));
        if (trialBalance.getIsFinal()){
            throw new CoolException("该记录已经赎回，不能再赎回");
        }
        //理财账户
        FinanceAccountEntity outAccount = getById(trialBalance.getAccountId());
        if (outAccount.getAccountBalance().compareTo(trialBalance.getCapital())<0){
            throw new CoolException("理财账户余额不足，赎回失败");
        }
        //更新理财账户余额
        outAccount.setAccountBalance(outAccount.getAccountBalance().add(trialBalance.getInterest()));
        updateById(outAccount);
        //开始转账
        FinanceTransferAccountVo params = new FinanceTransferAccountVo();
        params.setTransferType(TransferType.REPAYMENT.getType());
        params.setOutAccountId(outAccount.getId());
        params.setInAccountId(outAccount.getRedeemAccount());
        params.setTransferMoney(trialBalance.getCapital().add(trialBalance.getInterest()));
        params.setRemark(StringUtils.isBlank(trialBalance.getRemark()) ? "自动赎回程序转入赎回账户" : trialBalance.getRemark());
        transfer(params);
        //注销账户
        outAccount.setIsRedeem(true);
        //全部赎回
        if (outAccount.getAccountBalance().compareTo(trialBalance.getCapital().add(trialBalance.getInterest()))==0){
            outAccount.setIsCancel(1);
            outAccount.setCancelDate(new Date());
        }else{
            outAccount.setAccountBalance(outAccount.getAccountBalance().subtract(trialBalance.getCapital().add(trialBalance.getInterest())));
        }
        updateById(outAccount);
        //设置为最终试算
        trialBalance.setIsFinal(true);
        trialBalance.setTrialDate(new Date());
        trialBalanceMapper.update(trialBalance);
        return true;
    }
}
